import datetime
import mongoengine as db
from nanoid import generate

from app.db.models.assets import Asset
from app.db.models.balances import Balances
from app.db import BaseDocument, BaseEmbeddedDocument
from app.errors import AddJobError, PackageLimit
from app.libs.enums import (
    SECURITY_EVENT_PLUGIN_TUPLE,
    PreLoginMethod,
    FOREIGN_LINKS_PLUGIN_TUPLE,
    SECURITY_EVENT_PLUGIN_FOREIGN_LINKS_TUPLE,
    CHANGE_CHECK_TYPE_TUPLE
)
from app.libs.utility import DEFAULT_AREA_TUPLE


def gen_list_field_default(func):
    f = func()
    return [f]


class Target(BaseEmbeddedDocument):
    """例子
    "target": {
        "protocol": "http:",
        "host": "rrrr.com:8080",
        "hostname": "rrrr.com",
        "port": 8080,
        "ipType": 0,
        "eTLD1": "rrrr.com"
    }
    """
    protocol = db.StringField(required=True, choices=[
        'https:', 'http:'], default='http:')
    host = db.StringField()
    hostname = db.StringField()
    port = db.LongField(min_value=1, max_value=65535, null=True)
    ipType = db.LongField(default=0)
    eTLD1 = db.StringField()


class AlertSettings(BaseEmbeddedDocument):
    """例子
        "alertSettings":{
        "enable":{
            "asset":true,
            "vul":true,
            "cyd":true,
            "ssl":true,
            "securityEvent":true,
            "http":true,
            "ping":true,
            "hostVul":true,
        },
        "notification":{
            "email":true,
            "sms":true,
            "wechat":true
        },
        "smsAllowedTime":{
            "start":"00:00:00",
            "end":"23:59:59"
        },
        "emailAllowedTime":{
            "start":"00:00:00",
            "end":"23:59:59"
        },
        "alertGroupIds":[
            "604d7940cefd469dfbfcb093"
        ],
        "smsDailyLimit":10,
        "emailDailyLimit":10
        }

    """
    enable = db.DictField(default={
        "asset": True,
        "vul": True,
        "cyd": True,
        "ssl": True,
        "securityEvent": True,
        "http": True,
        "ping": True,
        "hostVul": True,
    })
    notification = db.DictField(default={
        "email": True,
        "sms": True,
        "wechat": True,
        "inBox": True
    })
    smsAllowedTime = db.DictField(default={
        "start": "00:00:00",
        "end": "23:59:59"
    })
    emailAllowedTime = db.DictField(default={
        "start": "00:00:00",
        "end": "23:59:59"
    })

    alertGroupIds = db.ListField(db.StringField(max_length=24))
    smsDailyLimit = db.LongField(min_value=0, default=10)
    emailDailyLimit = db.LongField(min_value=0, default=10)


class Verification(BaseEmbeddedDocument):
    """例子
        "verification":{
        "isVerified":false,
        "challenge":"_BTjlhME0ZI84OL6T9S32"
        }
    """
    isVerified = db.BooleanField(default=False)
    challenge = db.StringField(default=generate)
    verifyType = db.StringField()
    verifiedTime = db.DateTimeField()
    note = db.StringField()

    meta = {
        'strict': False
    }


class VulSettingCollect(BaseEmbeddedDocument):
    """""collect":{
            "type":"increment"
        },

    """
    type = db.StringField(required=True, choices=[
        'full', 'increment'], default='increment')
    depth = db.IntField(min_value=0, default=3)
    maxPage = db.LongField(min_value=0, default=1000)
    speed = db.StringField(choices=['high', 'medium', 'low'], default=None)
    vul = db.ListField(db.StringField(default=None), defalut=None)
    includeUrl = db.ListField(db.StringField(default=None), defalut=None)


class VulAlert(BaseEmbeddedDocument):
    vulType = db.ListField(default=[
        "file_upload",
        "directory_listing",
        "xss",
        "directory_traversal",
        "code_execution",
        "csrf",
        "file_inclusion",
        "injection",
        "configuration",
        "information_disclosure",
        "command_execution",
        "malware",
        "webvul"
    ])
    meta = {
        'abstract': True,
        'strict': False
    }


class CustomVulAlert(VulAlert):
    enable = db.BooleanField(default=True)


class SpecialVulAlert(BaseEmbeddedDocument):
    enable = db.BooleanField(default=True)
    vulLevel = db.DictField(default=dict)


class VulSettings(BaseEmbeddedDocument):
    """
    "vulSettings":{
        "interval":
        "enableSitePortraitTriggerMonitor":false,
        "enable":true,
        "collect":
        "alert":
    },


    """
    interval = db.LongField(min_value=0, default=86400000)
    enableSitePortraitTriggerMonitor = db.BooleanField(default=False)
    enable = db.BooleanField(default=False)
    collect = db.EmbeddedDocumentField(
        VulSettingCollect, default=VulSettingCollect)
    alert = db.EmbeddedDocumentField(VulAlert, default=VulAlert)
    taskId = db.StringField(default='')
    vulType = db.StringField(default='')


class CustomVulSettings(BaseEmbeddedDocument):
    collect = db.EmbeddedDocumentField(
        VulSettingCollect, default=VulSettingCollect)
    alert = db.EmbeddedDocumentField(CustomVulAlert, default=CustomVulAlert)
    enableSitePortraitTriggerMonitor = db.BooleanField(default=False)
    vulType = db.StringField(default="all")


class SpecialVulSettings(BaseEmbeddedDocument):
    collect = db.EmbeddedDocumentField(
        VulSettingCollect, default=VulSettingCollect)
    alert = db.EmbeddedDocumentField(
        SpecialVulAlert, default=SpecialVulAlert)
    enableSitePortraitTriggerMonitor = db.BooleanField(default=False)


class SslSettingCollect(BaseEmbeddedDocument):
    """
    "collect":{
            "pluginCategories":[
                "certificate",
                "protocol"
            ]
        }

    """
    pluginCategories = db.ListField(choices=['certificate', 'protocol'], default=[
        'certificate', 'protocol'])


class SslSettingAlert(BaseEmbeddedDocument):
    """
    "alert":{
            "enable":true
        }

    """
    enable = db.BooleanField(default=True)
    meta = {
        'strict': False
    }


class SslSettings(BaseEmbeddedDocument):
    """
    "sslSettings":{
        "interval":,
        "enableSitePortraitTriggerMonitor":false,
        "enable":true,
        "collect":
    }

    """
    interval = db.LongField(min_value=0, default=86400000)
    enableSitePortraitTriggerMonitor = db.BooleanField(default=False)
    enable = db.BooleanField(default=False)
    collect = db.EmbeddedDocumentField(
        SslSettingCollect, default=SslSettingCollect)
    alert = db.EmbeddedDocumentField(SslSettingAlert, default=None)
    sourceIp = db.StringField()
    name = db.StringField()
    target = db.StringField()
    taskId = db.StringField(default='')


class CustomSslSettings(BaseEmbeddedDocument):
    """[summary]

    Returns:
        [type]: [description]
    """
    alert = db.EmbeddedDocumentField(SslSettingAlert, default=SslSettingAlert)
    collect = db.EmbeddedDocumentField(
        SslSettingCollect, default=SslSettingCollect)


class SecurityEventSettingCollect(BaseEmbeddedDocument):
    """
    "collect":{
            "plugins":[
                "black_links",
                "cryjack",
                "malscan",
                "broken_links"
            ],
            "depth":3,
            "maxPage":1000,
            "speed":"high"
        }

    """
    plugins = db.ListField(
        choices=SECURITY_EVENT_PLUGIN_TUPLE + FOREIGN_LINKS_PLUGIN_TUPLE,
        default=SECURITY_EVENT_PLUGIN_FOREIGN_LINKS_TUPLE)
    depth = db.IntField(min_value=0, default=3)
    maxPage = db.LongField(min_value=0, default=1000)
    speed = db.StringField(choices=['high', 'medium', 'low'], default='high')


class SecurityEventSettings(BaseEmbeddedDocument):
    """
    "securityEventSettings":{
        "interval":,
        "enableSitePortraitTriggerMonitor":false,
        "enable":true,
        "collect":
    },

    """
    interval = db.LongField(min_value=0, default=86400000)
    enableSitePortraitTriggerMonitor = db.BooleanField(default=False)
    enable = db.BooleanField(default=False)
    collect = db.EmbeddedDocumentField(
        SecurityEventSettingCollect, default=SecurityEventSettingCollect)
    taskId = db.StringField(default='')

    meta = {
        'strict': False,
    }


class CustomSecurityEventSettings(BaseEmbeddedDocument):
    alert = db.EmbeddedDocumentField(SslSettingAlert, default=SslSettingAlert)
    collect = db.EmbeddedDocumentField(
        SecurityEventSettingCollect, default=SecurityEventSettingCollect)


class ContentSettingCollect(BaseEmbeddedDocument):
    plugins = db.ListField(choices=["keyword", "privacy_disclosure"], default=["keyword", "privacy_disclosure"])
    depth = db.IntField(min_value=0, default=3)
    maxPage = db.LongField(min_value=0, default=1000)
    # speed = db.StringField(choices=['high', 'medium', 'low'], default='high')
    includeUrl = db.ListField(db.StringField(default=None), defalut=None)
    customId = db.StringField()
    systemKeywordTypes = db.ListField(choices=[1, 2, 3, 4, 5, 6, 7, 8, 9], default=[1, 2, 3, 4, 5, 6, 7, 8, 9])
    customKeywordTypes = db.ListField(
        choices=[1, 2, 3, 4, 5, 6, 7, 8, 9], default=[1, 2, 3, 4, 5, 6, 7, 8, 9])  # 关键词监测类型, 不传代表所有
    privacyDisclosureTypes = db.ListField(choices=[1, 2, 3, 4], default=[1, 2, 3, 4])  # 隐私监测类型, 不传代表所有


class ContentSettings(BaseEmbeddedDocument):
    interval = db.LongField(min_value=0, default=86400000)
    enableSitePortraitTriggerMonitor = db.BooleanField(default=False)
    enable = db.BooleanField(default=False)
    collect = db.EmbeddedDocumentField(ContentSettingCollect, default=ContentSettingCollect)
    taskId = db.StringField(default='')


class CustomContentSettings(BaseEmbeddedDocument):
    alert = db.EmbeddedDocumentField(SslSettingAlert, default=SslSettingAlert)
    collect = db.EmbeddedDocumentField(
        ContentSettingCollect, default=ContentSettingCollect)


class ChangeCheckSettingCollect(BaseEmbeddedDocument):
    depth = db.IntField(min_value=1, default=3)  # 最大监测深度
    maxPage = db.IntField(min_value=1, default=100)  # 最大监测页面数
    enableBaseChange = db.BooleanField(default=True)  # 是否自动变更样本
    baseChangeCount = db.IntField(min_value=2, default=5)  # 自动变更样本频率
    keywords = db.ListField(default=[])  # 自定义违规词
    resources = db.ListField(default=[])  # 重点关注资源
    changeLevel = db.IntField()  # 变更级别， 预留字段， 一期不实现具体功能
    changeType = db.ListField(default=list(CHANGE_CHECK_TYPE_TUPLE), choices=CHANGE_CHECK_TYPE_TUPLE)  # 变更类型
    type = db.StringField(required=True, choices=['full', 'part'], default='full')  # 监测方式
    includeUrl = db.ListField(default=[])  # 指定监测页面
    excludeUrl = db.ListField(default=[])  # 不监测页面
    textChangeRatio = db.FloatField()  # 内容变更比例
    structureChangeRatio = db.FloatField()  # 结构变更比例
    resourceChangeRatio = db.FloatField()  # 资源变更比例


class ChangeCheckSettings(BaseEmbeddedDocument):
    interval = db.LongField(min_value=0, default=86400000)
    enable = db.BooleanField(default=False)
    collect = db.EmbeddedDocumentField(ChangeCheckSettingCollect, default=ChangeCheckSettingCollect)
    taskId = db.StringField(default='')


class HttpSettingCollect(BaseEmbeddedDocument):
    """
    {
                "area":[
                    "beijing-cmc",
                    "beijing-cuc",
                    "chengdu-cmc",
                    "chongqing-cuc",
                    "kunming-ctc"
                ],
                "method":"get",
                "redirect":3
            }

    """
    area = db.ListField(default=DEFAULT_AREA_TUPLE)  # 可用性任务监测节点
    area_ipv6 = db.ListField(default=[])  # ipv6
    method = db.StringField(
        choices=['head', 'get', 'post', 'put'], default='get')
    header = db.DynamicField()
    redirect = db.LongField(min_value=0, max_value=10, default=3)
    payload = db.StringField()


class HttpSettingAlert(BaseEmbeddedDocument):
    """
    {
        "respTime":12000,
        "innerType":"statusCodeRange",
        "statusCodeRange":,
        "nodeCount":5,
        "alertCount":1,
        "enableSmartMode":true
            }

    """
    respTime = db.LongField(default=12000, min_value=1)
    enableSmartMode = db.BooleanField(default=True)
    innerType = db.StringField(default='statusCodeRange')
    statusCodeRange = db.ListField(default=[[400, 599]])
    include = db.ListField(db.StringField())
    nodeCount = db.LongField(min_value=1, default=1)
    alertCount = db.LongField(min_value=1, default=1, max_value=5)
    enable = db.BooleanField(default=False)
    lossRate = db.LongField(min_value=1, max_value=100, default=50)


class HttpSettings(BaseEmbeddedDocument):
    """
        {
            "enableSitePortraitTriggerMonitor":false,
            "enable":true,
            "name":"首页",
            "target":"https://test33333.com/",
            "collect":,
            "alert":,
            "interval":,
            "sourceIp":"101.56.3.25"
        }
    """
    enableSitePortraitTriggerMonitor = db.BooleanField(default=False)
    enable = db.BooleanField(default=False)
    name = db.StringField(max_length=120, default='首页', required=True)
    target = db.StringField(default="")
    collect = db.EmbeddedDocumentField(
        HttpSettingCollect, default=HttpSettingCollect)
    alert = db.EmbeddedDocumentField(
        HttpSettingAlert, default=HttpSettingAlert)
    interval = db.LongField(min_value=0, default=900000)
    sourceIp = db.StringField()
    taskId = db.StringField(default='')


class PingSettingCollect(BaseEmbeddedDocument):
    """
    {
                "area":[
                    "beijing-cmc",
                    "beijing-cuc",
                    "chengdu-cmc",
                    "chongqing-cuc",
                    "dongguan-cuc"
                ]

    """
    area = db.ListField(default=DEFAULT_AREA_TUPLE)  # 可用性任务监测节点
    area_ipv6 = db.ListField(default=[])


class PingSettingAlert(BaseEmbeddedDocument):
    """
    {
        "respTime":1000,
        "lossRate":50,
        "nodeCount":5,
        "alertCount":1
    }

    """
    respTime = db.LongField(default=1000, min_value=1)
    lossRate = db.LongField(min_value=1, max_value=100, default=50)
    nodeCount = db.LongField(min_value=1, default=5)
    alertCount = db.LongField(min_value=1, default=1, max_value=5)
    enable = db.BooleanField(default=True)


class PingSettings(BaseEmbeddedDocument):
    """
    "enableSitePortraitTriggerMonitor":false,
    "enable":true,
    "name":"默认",
    "sourceIp":"101.56.3.25",
    "target":"test33333.com",
    "collect":,
    "alert":,
    "interval":

    """
    enableSitePortraitTriggerMonitor = db.BooleanField(default=False)
    enable = db.BooleanField(default=False)
    name = db.StringField(max_length=120, default='默认', required=True)
    sourceIp = db.StringField(max_length=120, default='')
    target = db.StringField(default="")
    collect = db.EmbeddedDocumentField(
        PingSettingCollect, default=PingSettingCollect)
    alert = db.EmbeddedDocumentField(
        PingSettingAlert, default=PingSettingAlert)
    interval = db.LongField(min_value=0, default=900000)
    taskId = db.StringField(default='')


class HttpAlertState(BaseEmbeddedDocument):
    """
    "httpAlertState":[
        {
            "securityStatus":"unknown",
            "sendCount":0,
            "_id":{
                "$oid":"6088c3885c63c5001ddc9a7c"
            },
            "firstSendTime":null,
            "lastSendTime":null
        }
    ],

    """
    securityStatus = db.StringField(default='unknown')
    sendCount = db.LongField(default=0)
    _id = db.ObjectIdField()
    firstSendTime = db.DateTimeField(default=None)
    lastSendTime = db.DateTimeField(default=None)


class PingAlertState(BaseEmbeddedDocument):
    """
    "pingAlertState":[
        {
            "securityStatus":"unknown",
            "sendCount":0,
            "_id":{
                "$oid":"6088c3885c63c5001ddc9a7d"
            },
            "firstSendTime":null,
            "lastSendTime":null
        }
    ]

    Args:

    """
    securityStatus = db.StringField(default='unknown')
    sendCount = db.LongField(default=0)
    _id = db.ObjectIdField()
    firstSendTime = db.DateTimeField(default=None)
    lastSendTime = db.DateTimeField(default=None)


class CustomMonitorPage(BaseEmbeddedDocument):
    includeUrl = db.ListField(db.StringField(), default=[])
    excludeUrl = db.ListField(db.StringField(), default=[])


class PreLogin(BaseEmbeddedDocument):
    site_login = db.BooleanField(default=False)
    login_method = db.StringField(default=PreLoginMethod.form.value, choices=[item.value for item in PreLoginMethod])
    login_json_action_url = db.StringField()
    login_json_postdata = db.StringField()
    login_form_action_url = db.StringField()
    login_form_postdata = db.StringField()
    request_cookie = db.StringField()
    request_http_headers = db.StringField()

    is_http_auth_enabled = db.BooleanField(default=False)
    http_auth_username = db.StringField()
    http_auth_password = db.StringField()

    is_proxy_enabled = db.BooleanField(default=False)
    is_proxy_need_auth = db.BooleanField(default=True)
    proxy_scheme = db.StringField(default='http', choices=['http'])
    proxy_host = db.StringField()
    proxy_port = db.IntField(default=80)
    proxy_username = db.StringField()
    proxy_password = db.StringField()
    # request_user_agent = db.StringField()


class ProxyIpResult(BaseEmbeddedDocument):
    task_type = db.StringField()
    ip = db.StringField(default="")
    runtime = db.DateTimeField()


class Job(BaseDocument):
    # _id = db.ObjectIdField(primary_key=True)
    assetType = db.StringField(default='web')
    alertSettings = db.EmbeddedDocumentField(AlertSettings, default=AlertSettings)
    verification = db.EmbeddedDocumentField(Verification, default=Verification)

    # vul
    vulSettings = db.EmbeddedDocumentField(VulSettings, default=VulSettings)
    vulAlertState = db.DictField(default={"securityStatus": "unknown", "sendCount": 0})
    vulIsStarted = db.BooleanField(default=False)
    vulResultId = db.ObjectIdField()
    vulSecurityStatus = db.StringField(default='unknown')

    # ssl
    sslSettings = db.EmbeddedDocumentField(SslSettings, default=SslSettings)
    sslAlertState = db.DictField(default={"securityStatus": "unknown", "sendCount": 0})
    sslIsStarted = db.BooleanField(default=False)
    sslResultId = db.ObjectIdField()
    sslSecurityStatus = db.StringField(default='unknown')

    # securityEvent
    securityEventSettings = db.EmbeddedDocumentField(SecurityEventSettings, default=SecurityEventSettings)
    securityEventAlertState = db.DictField(default={"securityStatus": "unknown", "sendCount": 0})
    securityEventIsStarted = db.BooleanField(default=False)
    securityEventResultId = db.ObjectIdField()
    securityEventSecurityStatus = db.StringField(default='unknown')

    # content
    contentSettings = db.EmbeddedDocumentField(ContentSettings, default=ContentSettings)
    contentAlertState = db.DictField(default={"securityStatus": "unknown", "sendCount": 0})
    contentIsStarted = db.BooleanField(default=False)
    contentResultId = db.ObjectIdField()
    contentPrevResultId = db.ObjectIdField()
    contentSecurityStatus = db.StringField(default='unknown')

    # changeCheck
    changeCheckSettings = db.EmbeddedDocumentField(ChangeCheckSettings, default=ChangeCheckSettings)
    changeCheckAlertState = db.DictField(default={"securityStatus": "unknown", "sendCount": 0})
    changeCheckIsStarted = db.BooleanField(default=False)
    changeCheckResultId = db.ObjectIdField()
    changeCheckSecurityStatus = db.StringField(default='unknown')

    # http
    httpSettings = db.EmbeddedDocumentListField(HttpSettings, default=gen_list_field_default(HttpSettings))
    httpStatusId = db.ListField(default=[None])
    httpIsStarted = db.ListField(db.BooleanField(default=False), default=[False])
    httpSecurityStatus = db.ListField(db.StringField(default='unknown'), default=['unknown'])
    httpPrevResultId = db.ListField(default=[None])
    httpResultId = db.ListField(default=[None])
    httpAbnormal = db.ListField(db.BooleanField(default=False), default=[False])
    httpNextExecDate = db.ListField(default=[None])
    httpAlertState = db.EmbeddedDocumentListField(HttpAlertState, default=gen_list_field_default(HttpAlertState))

    # ping
    pingSettings = db.EmbeddedDocumentListField(PingSettings, default=gen_list_field_default(PingSettings))
    pingStatusId = db.ListField(default=[None])
    pingIsStarted = db.ListField(db.BooleanField(default=False), default=[False])
    pingSecurityStatus = db.ListField(db.StringField(default='unknown'), default=['unknown'])
    pingPrevResultId = db.ListField(default=[None])
    pingResultId = db.ListField(default=[None])
    pingAbnormal = db.ListField(db.BooleanField(default=False), default=[False])
    pingNextExecDate = db.ListField(default=[None])
    pingAlertState = db.EmbeddedDocumentListField(PingAlertState, default=gen_list_field_default(PingAlertState))

    # 资产安全状态
    securityStatus = db.DictField(default={"level": "未知", "score": 0, "update_time": ""})
    isSupportIpv6 = db.StringField(default='unknown')
    ipv6Score = db.IntField(default=0, min_value=0, max_value=100)

    # asset
    assetId = db.ObjectIdField()
    assetResultId = db.ObjectIdField()

    note = db.StringField(max_length=50, default='')
    enableMonitor = db.BooleanField(default=False)
    enableAlert = db.BooleanField(default=False)
    cydEnabled = db.BooleanField(default=False)
    uid = db.ObjectIdField(required=True)
    target = db.EmbeddedDocumentField(Target, default=Target)
    targetUrl = db.StringField()
    # httpSettings = db.ListField(db.EmbeddedDocumentField(HttpSettings), default=HttpSettings)
    sourceIp = db.StringField()
    createTime = db.DateTimeField()
    sitePortraitId = db.ObjectIdField()
    import_type = db.StringField(default='')
    dns_id = db.StringField(default='')
    site_id = db.StringField(default='')
    ignoredWarnIdMap = db.DictField(default={})
    cookie = db.StringField(default='')  # Banished
    customMonitorPage = db.EmbeddedDocumentField(CustomMonitorPage, default=CustomMonitorPage)
    prelogin = db.EmbeddedDocumentField(PreLogin, default=PreLogin)
    defense_target_id = db.ObjectIdField()  # 是否云防御源站安全检测增加的资产
    enable_proxy_ip = db.BooleanField(default=False)  # 是否开启代理IP监测
    proxy_ip_result = db.EmbeddedDocumentListField(ProxyIpResult, default=[])  # 记录资产最新执行任务的IP代理详情

    meta = {
        'collection': 'jobs',
        'strict': False
    }

    def clean(self):
        if not self.note:
            raise AddJobError(msg='资产名称不能为空')
        elif len(self.note) > 50:
            raise AddJobError(msg='资产名称不超过50个字符')

        # 套餐检查, 云防御源站安全检测加入的资产不用查询套餐信息
        if self._created and not self.defense_target_id:
            if balance := Balances.objects.filter(uid=self.uid).first():
                if self.assetType == 'web':
                    if balance.balance.domain.used >= balance.balance.domain.total:
                        raise PackageLimit(msg='超出套餐限制')
                else:
                    if balance.balance.host.used >= balance.balance.host.total:
                        raise PackageLimit(msg='超出套餐限制')
            else:
                raise AddJobError(msg='未找到套餐信息')

        # 兼容安全事件外链plugins
        plugins = self.securityEventSettings.collect.plugins
        if "foreign_links" in plugins:
            plugins.remove("foreign_links")
            plugins.extend(list(FOREIGN_LINKS_PLUGIN_TUPLE))

        # 资产存在检查
        if self._created and Job.objects.filter(
                uid=self.uid,
                sourceIp=self.sourceIp,
                target__protocol=self.target.protocol,
                target__hostname=self.target.hostname,
                target__port=self.target.port
        ).first():
            raise AddJobError(msg='重复添加')
        return super().clean()

    def save(self, *args, **kwargs):
        if not self.createTime:
            self.createTime = datetime.datetime.utcnow()
        return super(Job, self).save(*args, **kwargs)

    def is_disabled(self, enable):
        """根据总开关, 认证状态, 和setting的状态, 判断配置是否应该禁用

        Args:
            enable ([type]): setting.enable

        Returns:
            [type]: [description]
        """
        return not (self.enableMonitor and self.verification.isVerified and enable)

    def get_asset(self):
        return Asset.objects.get_or_404(pk=self.assetId)

    def get_task_ids(self, asset=None):
        all_task_ids = set()
        all_task_ids.add(self.vulSettings.taskId)
        all_task_ids.add(self.securityEventSettings.taskId)
        all_task_ids.add(self.sslSettings.taskId)
        all_task_ids.add(self.contentSettings.taskId)
        for setting in self.httpSettings:
            all_task_ids.add(setting.taskId)
        for setting in self.pingSettings:
            all_task_ids.add(setting.taskId)
        # 主机资产无self.assetId, self.get_asset()会导致500
        if not asset and self.assetId:
            asset = self.get_asset()
        if asset:
            all_task_ids.add(asset.taskSettings.taskId)
        if '' in all_task_ids:
            all_task_ids.remove('')
        if None in all_task_ids:
            all_task_ids.remove(None)
        return all_task_ids
